package pl.lsierant.j2me.bipacz.intervaltimer;

import pl.lsierant.j2me.bipacz.log.Logger;
import pl.lsierant.j2me.bipacz.timer.ITimerUI;

/*
 * FIXME better timer implementation/interval dispatcher 
 */
public class IntervalTimerThread extends Thread {
    private final Logger logger = new Logger("TaskLoopThread");

    private long startTime;
    private IntervalTimerDef intervalTimerDef;
    private ITimerUI timerUI;

    private volatile boolean running;

    public IntervalTimerThread(IntervalTimerDef intervalTimerDef, ITimerUI timerUI) {
        this.intervalTimerDef = intervalTimerDef;
        this.timerUI = timerUI;
    }

    public synchronized void start() {
        timerUI.updateTime(0);
        startTime = System.currentTimeMillis();
        running = true;
        super.start();
    }

    public void run() {
        try {
            logger.log("run");
            for (int i = 0; i < intervalTimerDef.getRepeat(); i++) {
                for (int currentIndex = 0; currentIndex < intervalTimerDef.size(); currentIndex++) {
                    Interval interval = intervalTimerDef.getInterval(currentIndex);
                    timerUI.setCurrentInterval(interval);
                    intervalStarted(interval);
                    runSleep(interval.getDuration());
                    if (!running) {
                        break;
                    }
                    intervalEnded(interval);
                }
                if (!running) {
                    break;
                }
            }
            logger.log("run EXIT");
        } catch (RuntimeException e) {
            e.printStackTrace();
            throw e;
        }
    }

    private void intervalStarted(final Interval interval) {
        new Thread(new Runnable() {
            public void run() {
                try {
                    long delta = System.currentTimeMillis() - startTime;
                    System.out.println("intervalStarted:" + interval.getName() + "@ " + (delta / 1000.0)
                            + " s.");
                    interval.onStart();
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.log("intervalStarted: " + e.getMessage());
                }
            }
        }).start();
    }

    private void intervalEnded(final Interval interval) {
        new Thread(new Runnable() {
            public void run() {
                try {
                    long delta = System.currentTimeMillis() - startTime;
                    System.out.println("intervalEnded:" + interval.getName() + "@ " + (delta / 1000.0)
                            + " s.");
                    interval.onEnd();
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.log("intervalEnded: " + e.getMessage());
                }
            }
        }).start();
    }

    private void runSleep(long sleep) {
        long startTime = System.currentTimeMillis();
        long sleepStep = 179;
        while (System.currentTimeMillis() - startTime < sleep && running) {
            try {
                long delta = sleep - (System.currentTimeMillis() - startTime);
                sleep(Math.min(sleepStep, delta));
                updateUI();
            } catch (InterruptedException e) {
                logger.log("Interrupted exception");
                running = false;
                break;
            }
        }
    }

    private void updateUI() {
        long delta = System.currentTimeMillis() - startTime;
        timerUI.updateTime(delta);
    }

    public synchronized boolean isRunning() {
        return running;
    }

    public void stop() {
        logger.log("stop");
        running = false;
    }
}
